import { useEffect, useMemo, useRef, useState } from 'react';
import type { ReactNode } from 'react';
import { z } from 'zod';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Switch } from '@/components/ui/switch';
import { Badge } from '@/components/ui/badge';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { toast } from '@/components/ui/sonner';
import { api } from '@/lib/api';
import {
  ClassInfo,
  PreviewField,
  ScaffoldFile,
  ScaffoldOptionsPayload,
  ScaffoldPayload,
  ScaffoldZipResult,
} from '@/types/scaffold';
import { Loader2, Download, FileCode, Database } from 'lucide-react';

const basicInfoSchema = z.object({
  basePackage: z.string().min(1, '请输入基础包名'),
  moduleName: z.string().min(1, '请输入模块名称'),
  moduleBasePath: z.string().min(1, '请输入模块路径'),
  enableBlockchain: z.boolean().default(false),
});

type BasicInfoForm = z.infer<typeof basicInfoSchema>;

const optionsSchema = z.object({
  author: z.string().optional(),
  moduleDescription: z.string().optional(),
  apiPrefix: z.string().optional(),
  frontendFramework: z.enum(['REACT', 'VUE']).default('REACT'),
  databaseType: z.enum(['H2', 'MYSQL']).default('H2'),
  databaseHost: z.string().optional(),
  databasePort: z
    .number({ invalid_type_error: '端口必须是数字' })
    .int()
    .positive()
    .max(65535)
    .optional(),
  databaseName: z.string().optional(),
  databaseUsername: z.string().optional(),
  databasePassword: z.string().optional(),
  databaseUrl: z.string().optional(),
  databaseDriverClassName: z.string().optional(),
});

type OptionsForm = z.infer<typeof optionsSchema>;

interface WizardState extends BasicInfoForm {
  createTableSql: string;
  options: OptionsForm;
}

const defaultState: WizardState = {
  basePackage: 'com.example.demo',
  moduleName: 'asset',
  moduleBasePath: 'modules/asset',
  enableBlockchain: false,
  createTableSql: '',
  options: {
    author: '',
    moduleDescription: '',
    apiPrefix: '',
    frontendFramework: 'REACT',
    databaseType: 'H2',
    databaseHost: 'localhost',
    databasePort: 3306,
    databaseName: 'demo',
    databaseUsername: 'sa',
    databasePassword: '',
    databaseDriverClassName: 'org.h2.Driver',
  },
};

const GenerateWizardPage = () => {
  const [state, setState] = useState<WizardState>(defaultState);
  const [previewFields, setPreviewFields] = useState<PreviewField[]>([]);
  const [previewFiles, setPreviewFiles] = useState<ScaffoldFile[]>([]);
  const [previewLoading, setPreviewLoading] = useState(false);
  const [zipLoading, setZipLoading] = useState(false);
  const [zipResult, setZipResult] = useState<ScaffoldZipResult | null>(null);
  const autoDownloadUrlRef = useRef<string | null>(null);

  const payload: ScaffoldPayload = useMemo(() => {
    const base: ScaffoldPayload = {
      basePackage: state.basePackage,
      moduleName: state.moduleName,
      moduleBasePath: state.moduleBasePath,
      createTableSql: state.createTableSql,
      scaffoldOptions: buildScaffoldOptions(state),
      sqlParseOptions: {},
    };
    return base;
  }, [state]);

  const updateBasic = <K extends keyof BasicInfoForm>(key: K, value: BasicInfoForm[K]) => {
    setState((prev) => ({
      ...prev,
      [key]: value,
    }));
  };

  const updateOption = <K extends keyof OptionsForm>(key: K, value: OptionsForm[K]) => {
    setState((prev) => ({
      ...prev,
      options: {
        ...prev.options,
        [key]: value,
      },
    }));
  };

  const validateBeforeGenerate = () => {
    const basicResult = basicInfoSchema.safeParse({
      basePackage: state.basePackage,
      moduleName: state.moduleName,
      moduleBasePath: state.moduleBasePath,
      enableBlockchain: state.enableBlockchain,
    });
    if (!basicResult.success) {
      toast.error(basicResult.error.issues[0]?.message ?? '基础信息校验失败');
      return false;
    }

    const optionsResult = optionsSchema.safeParse(state.options);
    if (!optionsResult.success) {
      toast.error(optionsResult.error.issues[0]?.message ?? '脚手架选项校验失败');
      return false;
    }

    if (!state.createTableSql.trim()) {
      toast.error('请输入建表 SQL');
      return false;
    }

    return true;
  };

  const handlePreviewFields = async () => {
    if (!state.createTableSql.trim()) {
      toast.warning('请先输入建表 SQL');
      return;
    }
    try {
      setPreviewLoading(true);
      const classInfo = await api.post<ClassInfo>('/generator/preview', {
        mode: 'create',
        sql: state.createTableSql,
        nameCaseType: 'CamelCase',
      });
      const fields = Array.isArray(classInfo.fieldList) ? classInfo.fieldList : [];
      setPreviewFields(fields);
      if (fields.length === 0) {
        toast.warning('未解析到字段，请检查 SQL 是否正确。');
      } else {
        toast.success('SQL 解析完成');
      }
    } catch (error) {
      toast.error(error instanceof Error ? error.message : '解析 SQL 失败');
    } finally {
      setPreviewLoading(false);
    }
  };

  const handleGeneratePreview = async () => {
    if (!validateBeforeGenerate()) {
      return;
    }
    try {
      setPreviewLoading(true);
      const files = await api.post<ScaffoldFile[]>('/generator/scaffold/files', payload);
      setPreviewFiles(files);
      if (files.length === 0) {
        toast.warning('没有生成任何文件，请检查配置。');
      } else {
        toast.success('文件预览生成成功');
      }
    } catch (error) {
      toast.error(error instanceof Error ? error.message : '生成预览失败');
    } finally {
      setPreviewLoading(false);
    }
  };

  const handleGenerateZip = async () => {
    if (!validateBeforeGenerate()) {
      return;
    }
    try {
      setZipLoading(true);
      const result = await api.post<ScaffoldZipResult>('/generator/scaffold/zip', payload);
      setZipResult(result);
      toast.success('ZIP 生成成功，可立即下载');
    } catch (error) {
      toast.error(error instanceof Error ? error.message : 'ZIP 生成失败');
    } finally {
      setZipLoading(false);
    }
  };

  const isMySQL = state.options.databaseType === 'MYSQL';

  useEffect(() => {
    if (!zipResult?.downloadUrl) {
      return;
    }
    if (autoDownloadUrlRef.current === zipResult.downloadUrl) {
      return;
    }
    const link = document.createElement('a');
    link.href = zipResult.downloadUrl;
    link.download = zipResult.zipFileName ?? 'scaffold-project.zip';
    link.rel = 'noopener';
    document.body.appendChild(link);
    link.click();
    link.remove();
    autoDownloadUrlRef.current = zipResult.downloadUrl;
  }, [zipResult]);

  useEffect(() => {
    if (state.options.databaseType === 'H2') {
      if (state.options.databaseDriverClassName !== 'org.h2.Driver') {
        updateOption('databaseDriverClassName', 'org.h2.Driver');
      }
      if (!state.options.databaseUsername || state.options.databaseUsername === 'root') {
        updateOption('databaseUsername', 'sa');
      }
    } else {
      if (!state.options.databaseDriverClassName || state.options.databaseDriverClassName === 'org.h2.Driver') {
        updateOption('databaseDriverClassName', 'com.mysql.cj.jdbc.Driver');
      }
      if (!state.options.databaseUsername || state.options.databaseUsername === 'sa') {
        updateOption('databaseUsername', 'root');
      }
    }
  }, [state.options.databaseType]);

  return (
    <div className="space-y-6">
      <div className="grid gap-6 xl:grid-cols-2 xl:items-stretch">
        <Card className="h-full">
          <CardHeader>
            <CardTitle>基础信息</CardTitle>
          </CardHeader>
          <CardContent>
            <div className="grid gap-6 md:grid-cols-2">
              <FieldGroup label="基础包">
                <Input
                  value={state.basePackage}
                  onChange={(event) => updateBasic('basePackage', event.target.value)}
                  placeholder="com.example.demo"
                />
              </FieldGroup>
              <FieldGroup label="模块名称">
                <Input
                  value={state.moduleName}
                  onChange={(event) => updateBasic('moduleName', event.target.value)}
                  placeholder="asset"
                />
              </FieldGroup>
              <FieldGroup label="模块目录" description="相对于基础包的业务路径，例如 modules/asset">
                <Input
                  value={state.moduleBasePath}
                  onChange={(event) => updateBasic('moduleBasePath', event.target.value)}
                  placeholder="modules/asset"
                />
              </FieldGroup>
              <div className="md:col-span-2">
                <FieldGroup label="生成区块链扩展">
                  <div className="flex items-center gap-2">
                    <Switch
                      checked={state.enableBlockchain}
                      onCheckedChange={(checked) => updateBasic('enableBlockchain', checked)}
                    />
                    <span className="text-sm text-muted-foreground">勾选后将额外生成链上相关模板与配置。</span>
                  </div>
                </FieldGroup>
              </div>
            </div>
          </CardContent>
        </Card>
        <Card className="h-full">
          <CardHeader>
            <CardTitle>建表 SQL</CardTitle>
          </CardHeader>
          <CardContent className="flex flex-col gap-4">
            <div className="space-y-2">
              <Label htmlFor="sql">CREATE TABLE 语句</Label>
              <Textarea
                id="sql"
                value={state.createTableSql}
                onChange={(event) => setState((prev) => ({ ...prev, createTableSql: event.target.value }))}
                rows={8}
                placeholder="CREATE TABLE asset (id BIGINT PRIMARY KEY, name VARCHAR(64));"
              />
            </div>

            <div className="flex flex-wrap items-center justify-between gap-3">
              <div className="space-x-2">
                <Button type="button" variant="outline" onClick={handlePreviewFields} disabled={previewLoading}>
                  {previewLoading ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : <Database className="mr-2 h-4 w-4" />}
                  解析字段
                </Button>
              </div>
            </div>

            <Card className="border-dashed">
              <CardHeader>
                <CardTitle className="text-sm">解析结果</CardTitle>
              </CardHeader>
              <CardContent className="p-0">
                {previewFields.length === 0 ? (
                  <div className="flex h-32 items-center justify-center text-sm text-muted-foreground">
                    暂无字段，请点击“解析字段”查看结果。
                  </div>
                ) : (
                  <ScrollArea className="max-h-64">
                    <Table>
                      <TableHeader>
                        <TableRow>
                          <TableHead>列名</TableHead>
                          <TableHead>字段名</TableHead>
                          <TableHead>Java 类型</TableHead>
                          <TableHead>备注</TableHead>
                        </TableRow>
                      </TableHeader>
                      <TableBody>
                        {previewFields.map((field) => (
                          <TableRow key={field.fieldName}>
                            <TableCell>{field.columnName}</TableCell>
                            <TableCell>{field.fieldName}</TableCell>
                            <TableCell>{field.fieldClass}</TableCell>
                            <TableCell className="text-xs text-muted-foreground">{field.fieldComment ?? '-'}</TableCell>
                          </TableRow>
                        ))}
                      </TableBody>
                    </Table>
                  </ScrollArea>
                )}
              </CardContent>
            </Card>
          </CardContent>
        </Card>
      </div>

      <div className="grid gap-6 xl:grid-cols-2 xl:items-stretch">
        <Card className="h-full">
          <CardHeader>
            <CardTitle>脚手架选项</CardTitle>
          </CardHeader>
          <CardContent>
            <div className="grid gap-6 md:grid-cols-2">
              <FieldGroup label="作者">
                <Input
                  value={state.options.author ?? ''}
                  onChange={(event) => updateOption('author', event.target.value)}
                  placeholder="可选"
                />
              </FieldGroup>
              <FieldGroup label="模块描述">
                <Input
                  value={state.options.moduleDescription ?? ''}
                  onChange={(event) => updateOption('moduleDescription', event.target.value)}
                  placeholder="资产管理模块"
                />
              </FieldGroup>
              <FieldGroup label="REST 前缀">
                <Input
                  value={state.options.apiPrefix ?? ''}
                  onChange={(event) => updateOption('apiPrefix', event.target.value)}
                  placeholder="asset"
                />
              </FieldGroup>
            <FieldGroup label="前端框架">
              <Select
                value={state.options.frontendFramework ?? 'REACT'}
                onValueChange={(value) => updateOption('frontendFramework', value as OptionsForm['frontendFramework'])}
              >
                <SelectTrigger>
                  <SelectValue placeholder="选择前端框架" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="REACT">React</SelectItem>
                  <SelectItem value="VUE">Vue</SelectItem>
                </SelectContent>
              </Select>
            </FieldGroup>
              <FieldGroup label="数据库类型">
                <Select
                  value={state.options.databaseType ?? 'H2'}
                  onValueChange={(value) => updateOption('databaseType', value as OptionsForm['databaseType'])}
                >
                  <SelectTrigger>
                    <SelectValue placeholder="选择数据库类型" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="H2">H2（内存）</SelectItem>
                    <SelectItem value="MYSQL">MySQL</SelectItem>
                  </SelectContent>
                </Select>
              </FieldGroup>

              {isMySQL && (
                <>
                  <FieldGroup label="数据库主机">
                    <Input
                      value={state.options.databaseHost ?? ''}
                      onChange={(event) => updateOption('databaseHost', event.target.value)}
                      placeholder="localhost"
                    />
                  </FieldGroup>
                  <FieldGroup label="数据库端口">
                    <Input
                      type="number"
                      value={state.options.databasePort ?? ''}
                      onChange={(event) => {
                        const value = event.target.value;
                        updateOption('databasePort', value ? Number(value) : undefined);
                      }}
                      placeholder="3306"
                    />
                  </FieldGroup>
                  <FieldGroup label="数据库名称">
                    <Input
                      value={state.options.databaseName ?? ''}
                      onChange={(event) => updateOption('databaseName', event.target.value)}
                      placeholder="demo"
                    />
                  </FieldGroup>
                  <FieldGroup label="用户名">
                    <Input
                      value={state.options.databaseUsername ?? ''}
                      onChange={(event) => updateOption('databaseUsername', event.target.value)}
                      placeholder="root"
                    />
                  </FieldGroup>
                  <FieldGroup label="密码">
                    <Input
                      type="password"
                      value={state.options.databasePassword ?? ''}
                      onChange={(event) => updateOption('databasePassword', event.target.value)}
                      placeholder="••••"
                    />
                  </FieldGroup>
                  <FieldGroup label="驱动类">
                    <Input
                      value={state.options.databaseDriverClassName ?? ''}
                      onChange={(event) => updateOption('databaseDriverClassName', event.target.value)}
                      placeholder="com.mysql.cj.jdbc.Driver"
                    />
                  </FieldGroup>
                  <FieldGroup label="自定义 JDBC URL" description="如填写，将覆盖 URL">
                    <Input
                      value={state.options.databaseUrl ?? ''}
                      onChange={(event) => updateOption('databaseUrl', event.target.value)}
                      placeholder="jdbc:mysql://..."
                    />
                  </FieldGroup>
                </>
              )}
            </div>
          </CardContent>
        </Card>
        <Card className="h-full">
          <CardHeader>
            <CardTitle>生成与下载</CardTitle>
          </CardHeader>
          <CardContent className="flex flex-col gap-6">
          <div className="rounded-lg border bg-muted p-4">
            <div className="text-sm font-medium text-foreground">生成摘要</div>
            <div className="mt-2 grid gap-2 text-xs text-muted-foreground md:grid-cols-2">
              <SummaryItem label="基础包" value={state.basePackage} />
              <SummaryItem label="模块名称" value={state.moduleName} />
              <SummaryItem label="模块目录" value={state.moduleBasePath} />
              <SummaryItem label="数据库类型" value={state.options.databaseType} />
              <SummaryItem label="区块链扩展" value={state.enableBlockchain ? '已启用' : '未启用'} />
              <SummaryItem label="前端框架" value={state.options.frontendFramework} />
            </div>
          </div>

            <div className="flex flex-wrap items-center gap-3">
              <Button variant="default" onClick={handleGeneratePreview} disabled={previewLoading}>
                {previewLoading ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : <FileCode className="mr-2 h-4 w-4" />}
                生成预览
              </Button>
              <Button variant="outline" onClick={handleGenerateZip} disabled={zipLoading}>
                {zipLoading ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : <Download className="mr-2 h-4 w-4" />}
                导出 ZIP
              </Button>
            </div>

            <PreviewSection files={previewFiles} loading={previewLoading} />

            {zipResult && (
              <Card className="border-primary/30 bg-primary/5">
                <CardHeader>
                  <CardTitle className="text-sm">ZIP 生成成功</CardTitle>
                </CardHeader>
                <CardContent className="space-y-2 text-sm">
                  <div className="flex items-center gap-2">
                    <span>文件名：</span>
                    <Badge variant="outline">{zipResult.zipFileName}</Badge>
                  </div>
                  <Button asChild size="sm">
                    <a href={zipResult.downloadUrl} target="_blank" rel="noreferrer">
                      点击下载
                    </a>
                  </Button>
                  <p className="text-xs text-muted-foreground">
                    ZIP 会在 TTL 到期后自动清理，如需长期保存，请及时下载或上传至制品库。
                  </p>
                </CardContent>
              </Card>
            )}
          </CardContent>
        </Card>
      </div>
    </div>
  );
};

const FieldGroup = ({
  label,
  description,
  error,
  children,
}: {
  label: string;
  description?: string;
  error?: string;
  children: ReactNode;
}) => (
  <div className="space-y-1">
    <Label className="text-sm font-medium text-foreground">{label}</Label>
    {children}
    {description ? <p className="text-xs text-muted-foreground">{description}</p> : null}
    {error ? <p className="text-xs text-destructive">{error}</p> : null}
  </div>
);

const PreviewSection = ({ files, loading }: { files: ScaffoldFile[]; loading: boolean }) => {
  if (loading) {
    return (
      <Card className="border-dashed">
        <CardHeader>
          <CardTitle className="text-sm">预览内容</CardTitle>
        </CardHeader>
        <CardContent className="h-48 animate-pulse bg-muted/20" />
      </Card>
    );
  }

  if (files.length === 0) {
    return (
      <Card className="border-dashed">
        <CardHeader>
          <CardTitle className="text-sm">预览内容</CardTitle>
        </CardHeader>
        <CardContent>
          <p className="text-sm text-muted-foreground">尚未生成预览文件。</p>
        </CardContent>
      </Card>
    );
  }

  return (
    <Card>
      <CardHeader>
        <CardTitle className="text-sm">文件预览</CardTitle>
      </CardHeader>
      <CardContent>
        <div className="flex flex-col gap-4">
          {files.map((file) => (
            <div key={file.path} className="rounded-lg border bg-muted/40">
              <div className="flex items-center justify-between border-b px-4 py-2 text-xs">
                <span className="font-medium text-foreground">{file.path}</span>
                <Badge variant="outline">{file.templateId}</Badge>
              </div>
              <ScrollArea className="max-h-72">
                <pre className="whitespace-pre-wrap break-words bg-background p-4 text-xs text-muted-foreground">
{file.content}
                </pre>
              </ScrollArea>
            </div>
          ))}
        </div>
      </CardContent>
    </Card>
  );
};

const SummaryItem = ({ label, value }: { label: string; value?: string }) => (
  <div className="flex flex-col">
    <span>{label}</span>
    <span className="font-medium text-foreground">{value ?? '-'}</span>
  </div>
);

function buildScaffoldOptions(state: WizardState): ScaffoldOptionsPayload {
  const { options } = state;
  return {
    author: options.author || undefined,
    moduleDescription: options.moduleDescription || undefined,
    apiPrefix: options.apiPrefix || undefined,
    enableBlockchain: state.enableBlockchain,
    frontendFramework: options.frontendFramework,
    databaseType: options.databaseType,
    databaseHost: options.databaseHost || undefined,
    databasePort: options.databasePort,
    databaseName: options.databaseName || undefined,
    databaseUsername: options.databaseUsername || undefined,
    databasePassword: options.databasePassword || undefined,
    databaseUrl: options.databaseUrl || undefined,
    databaseDriverClassName: options.databaseDriverClassName || undefined,
  };
}

export default GenerateWizardPage;
